feat: support needs[].parallel.matrix and matrix expressions - #1848
Merged
Conversation
Implements two related GitLab CI features for jobs whose producer or consumer uses parallel.matrix, mirroring upstream gitlab-org/gitlab behavior (MRs !118839 for the static layer, !205247 for matrix expressions): 1. Static needs[].parallel.matrix selectors (closes firecow#843): pick specific producer permutations to depend on, instead of all of them. Supports partial selectors (mention a subset of the producer's matrix keys), array-valued selectors (cartesian expansion), and honors `optional: true` when the selector matches zero permutations. 2. Matrix expressions ($[[ matrix.IDENTIFIER ]]) inside selectors, resolved per consumer permutation, enabling 1:1 dependency mapping between matched permutations. Supports the bare canonical form (`X: $[[ matrix.X ]]`) and array-wrapped form, multiple expressions concatenated in one string, identifiers containing letters, digits, underscore, and hyphen (matching upstream's `[a-zA-Z0-9_-]+` charset), and whitespace variations inside `$[[ ... ]]`. Errors are surfaced clearly for: producer without parallel:matrix (including plain `parallel: <int>`), selector matching zero permutations on a non-optional need, $[[ matrix.X ]] in a consumer that is not parallel:matrix, and $[[ matrix.X ]] referencing an identifier the consumer's matrix doesn't define (error wording mirrors upstream's "'<X>' does not exist in matrix configuration"). Tests cover the canonical example from gitlab-org/gitlab#423553 verbatim plus the upstream RSpec cases from spec/lib/gitlab/ci/config/interpolation/matrix_interpolator_spec.rb adapted to gitlab-ci-local's integration-test infrastructure. See https://docs.gitlab.com/ci/yaml/#needsparallelmatrix and https://docs.gitlab.com/ci/yaml/matrix_expressions/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
firecow
approved these changes
May 9, 2026
firecow
left a comment
Owner
There was a problem hiding this comment.
Reviewed the diff: implements needs[].parallel.matrix selectors and $[[ matrix.X ]] expressions to match upstream GitLab semantics (16.3, 18.6/18.8). Helpers cleanly isolated in src/parallel.ts, error messages mirror upstream wording, regex charset matches upstream's MatrixInterpolator, test coverage covers the artifact cascade and four explicit error paths. LGTM.
tmeijn
pushed a commit
to tmeijn/dotfiles
that referenced
this pull request
May 13, 2026
This MR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Adoption](https://docs.renovatebot.com/merge-confidence/) | [Passing](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---|---|---| | [npm:gitlab-ci-local](https://github.com/firecow/gitlab-ci-local) | `4.71.0` → `4.72.0` |  |  |  |  | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>firecow/gitlab-ci-local (npm:gitlab-ci-local)</summary> ### [`v4.72.0`](https://github.com/firecow/gitlab-ci-local/releases/tag/4.72.0) [Compare Source](firecow/gitlab-ci-local@4.71.0...4.72.0) #### What's Changed - feat: support spec:inputs for root pipeline via --input and --inputs-file by [@​gyanranjan](https://github.com/gyanranjan) in [#​1814](firecow/gitlab-ci-local#1814) - feat: implement workflow:rules:variables support ([#​1832](firecow/gitlab-ci-local#1832)) by [@​bcouetil](https://github.com/bcouetil) in [#​1833](firecow/gitlab-ci-local#1833) - chore(deps): lock file maintenance by [@​renovate](https://github.com/renovate)\[bot] in [#​1834](firecow/gitlab-ci-local#1834) - chore(deps): update all non-major by [@​renovate](https://github.com/renovate)\[bot] in [#​1835](firecow/gitlab-ci-local#1835) - fix: pass artifact paths to rsync via `--files-from` by [@​Paul-Goulpie](https://github.com/Paul-Goulpie) in [#​1825](firecow/gitlab-ci-local#1825) - chore(deps): update sonarsource/sonarqube-scan-action action to v8 by [@​renovate](https://github.com/renovate)\[bot] in [#​1842](firecow/gitlab-ci-local#1842) - fix: connect service containers to local registry network by [@​firecow](https://github.com/firecow) in [#​1847](firecow/gitlab-ci-local#1847) - test: ignore 'still running' heartbeat in stdout assertions by [@​firecow](https://github.com/firecow) in [#​1851](firecow/gitlab-ci-local#1851) - chore(deps): update github/codeql-action action to v4.35.4 by [@​renovate](https://github.com/renovate)\[bot] in [#​1843](firecow/gitlab-ci-local#1843) - chore(deps): lock file maintenance by [@​renovate](https://github.com/renovate)\[bot] in [#​1845](firecow/gitlab-ci-local#1845) - feat: add environment column to --list and --list-csv ([#​1837](firecow/gitlab-ci-local#1837)) by [@​bcouetil](https://github.com/bcouetil) in [#​1838](firecow/gitlab-ci-local#1838) - feat: support needs\[].parallel.matrix and matrix expressions by [@​inistor](https://github.com/inistor) in [#​1848](firecow/gitlab-ci-local#1848) - fix: reject empty rules array instead of silently skipping job by [@​firecow](https://github.com/firecow) in [#​1852](firecow/gitlab-ci-local#1852) - fix: respect IGNORE\_PREDEFINED\_VARS in .gitlab-ci-local-env by [@​firecow](https://github.com/firecow) in [#​1853](firecow/gitlab-ci-local#1853) - fix: reject ${VAR} in rules:if by [@​firecow](https://github.com/firecow) in [#​1854](firecow/gitlab-ci-local#1854) - fix: wait for child stdio close before resolving exec by [@​firecow](https://github.com/firecow) in [#​1855](firecow/gitlab-ci-local#1855) - chore: pin third-party actions to commit SHAs by [@​firecow](https://github.com/firecow) in [#​1857](firecow/gitlab-ci-local#1857) #### New Contributors - [@​gyanranjan](https://github.com/gyanranjan) made their first contribution in [#​1814](firecow/gitlab-ci-local#1814) - [@​inistor](https://github.com/inistor) made their first contribution in [#​1848](firecow/gitlab-ci-local#1848) **Full Changelog**: <firecow/gitlab-ci-local@4.71.0...4.72.0> </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzMuNSIsInVwZGF0ZWRJblZlciI6IjQzLjE3My41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6bWlub3IiXX0=-->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds support for two related GitLab CI features for parallel-matrix jobs:
Static
needs[].parallel.matrixselectors — pick specific producer permutations to depend on (closes Implement needs[].parallel.matrix #843). Shipped upstream in GitLab 16.3 (gitlab-org/gitlab!118839).Matrix expressions
$[[ matrix.IDENTIFIER ]]inside selectors — resolved per consumer permutation, enabling 1:1 dependency mapping across stages. Shipped upstream as Beta in GitLab 18.6, GA in 18.8 (gitlab-org/gitlab!205247 + flag removal in !209773).The original schema already permits
needs[].parallel(refsparallel_matrix), so no schema patch is needed.What works
Layer 1 — static selectors
parallel.matrix: [{NAME: foo}]selects onlybuild-job: [foo][{NAME: [foo, bar]}]optional: trueskips silently when the selector matches zero permutationsLayer 2 — matrix expressions
PROVIDER: $[[ matrix.PROVIDER ]](matches the example in gitlab-org/gitlab#423553)PROVIDER: ['$[[ matrix.PROVIDER ]]']TAG: build-$[[ matrix.OS ]]-$[[ matrix.STACK ]][a-zA-Z0-9_-]+regex inMatrixInterpolator)$[[ ... ]]Errors
parallel:matrix(including plainparallel: <int>)$[[ matrix.X ]]in a consumer that is not parallel-matrix$[[ matrix.X ]]referencing an identifier the consumer's matrix doesn't define — wording mirrors upstream's'X' does not exist in matrix configurationfor log grep parityTests
Six new fixtures under
tests/test-cases/, 18 integration tests total:needs-parallel-matrix-staticneeds-parallel-matrix-errorparallel: <int>producer, zero-match non-optionalneeds-parallel-matrix-expressionsneeds-parallel-matrix-expressions-non-parallel-consumerneeds-parallel-matrix-expressions-unknown-identifierneeds-parallel-matrix-artifactsThe matrix-expressions fixtures mirror the cases in upstream's
spec/lib/gitlab/ci/config/interpolation/matrix_interpolator_spec.rbadapted to gitlab-ci-local's integration-test infrastructure.Behavior note: partial selectors
The original #254821 issue description marked partial selectors (selector mentions only a subset of the producer's matrix keys) as "out of scope". This implementation supports them: a selector key list is treated as a constraint, with the producer's unmentioned keys free to take any value. This is also the behavior implied by upstream's matrix-expression test fixtures (which show partial-key shapes working) and is the more useful pattern when combined with
$[[ matrix.X ]]substitution.Happy to tighten this if you'd prefer strict full-selector semantics — let me know.
Out of scope (follow-ups if requested)
spec:headers / inputs expressions (separate code path that already lives in this project)String(v)coercion but lack an explicit fixtureextends:propagation ofneeds[].parallel.matrix(likely works via existing deepExtend, untested)References
Test plan
bun run typecheckbun run lintbunx vitest run tests/test-cases/needs-parallel-matrix-*Acknowledgment
This PR was implemented with assistance from Claude (Anthropic) as a pair-programming tool. The implementation was audited against upstream
gitlab-org/gitlabMRs and test files (notably !118839 and !205247) to ensure behavior parity with GitLab Runner's own logic. All code and tests were reviewed by me before pushing; CI on the internal fork PR confirmed the full vitest suite and four Node/Bun smoke matrix variants pass on Linux. Co-authorship is preserved in the commit trailer.Summary by cubic
Adds support for needs[].parallel.matrix selectors and $[[ matrix.X ]] expressions. This enables precise, 1:1 dependency mapping across parallel.matrix jobs and ensures artifacts flow only from matched permutations.
Written for commit 772dfaf. Summary will update on new commits.